home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / Src / Ch12 / vbdPgon.cls < prev    next >
Text File  |  1999-06-18  |  13KB  |  422 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4.   Persistable = 0  'NotPersistable
  5.   DataBindingBehavior = 0  'vbNone
  6.   DataSourceBehavior  = 0  'vbNone
  7.   MTSTransactionMode  = 0  'NotAnMTSObject
  8. END
  9. Attribute VB_Name = "vbdPolygon"
  10. Attribute VB_GlobalNameSpace = False
  11. Attribute VB_Creatable = True
  12. Attribute VB_PredeclaredId = False
  13. Attribute VB_Exposed = False
  14. Option Explicit
  15. ' VbDraw Polygon/Polyline object.
  16.  
  17. Implements vbdObject
  18.  
  19. Private Enum vbdPolygonErrors
  20.     errInvalidIndex = 381   ' Invalid property array index.
  21. End Enum
  22.  
  23. ' Indicates a closed polygon rather than a polyline.
  24. Public IsClosed As Boolean
  25.  
  26. ' The surface on which the user is clicking
  27. ' to define the object. This is set only during
  28. ' creation of this object.
  29. Public WithEvents m_Canvas As PictureBox
  30. Attribute m_Canvas.VB_VarHelpID = -1
  31. Private m_DrawingStarted As Boolean
  32.  
  33. ' Drawing properties.
  34. Private m_DrawWidth As Integer
  35. Private m_DrawStyle As DrawStyleConstants
  36. Private m_ForeColor As OLE_COLOR
  37. Private m_FillColor As OLE_COLOR
  38. Private m_FillStyle As FillStyleConstants
  39. Private m_Selected As Boolean
  40.  
  41. ' Data variables.
  42. Private m_NumPoints As Long
  43. Private m_OriginalPoints() As POINTAPI
  44. Private m_TransformedPoints() As POINTAPI
  45. Private m_M(1 To 3, 1 To 3) As Single
  46.  
  47. ' Rubberband variables.
  48. Private m_StartX As Single
  49. Private m_StartY As Single
  50. Private m_LastX As Single
  51. Private m_LastY As Single
  52. ' Return the number of points.
  53. Public Property Get NumPoints() As Integer
  54.     NumPoints = m_NumPoints
  55. End Property
  56.  
  57. ' Set the number of points.
  58. Public Property Let NumPoints(ByVal new_value As Integer)
  59.     m_NumPoints = new_value
  60.     If m_NumPoints < 1 Then
  61.         Erase m_OriginalPoints
  62.     Else
  63.         ReDim Preserve m_OriginalPoints(1 To m_NumPoints)
  64.     End If
  65. End Property
  66. ' Return an X coordinate.
  67. Property Get X(ByVal Index As Integer) As Single
  68.     If (Index < 1) Or (Index > m_NumPoints) Then
  69.         Err.Raise errInvalidIndex, "vbdPolygon.X"
  70.     End If
  71.  
  72.     X = m_OriginalPoints(Index).X
  73. End Property
  74. ' Set an X coordinate.
  75. Property Let X(ByVal Index As Integer, ByVal new_value As Single)
  76.     If (Index < 1) Or (Index > NumPoints) Then
  77.         Err.Raise errInvalidIndex, "vbdPolygon.X"
  78.     End If
  79.  
  80.     m_OriginalPoints(Index).X = new_value
  81. End Property
  82.  
  83. ' Return a Y coordinate.
  84. Property Get Y(ByVal Index As Integer) As Single
  85.     If (Index < 1) Or (Index > m_NumPoints) Then
  86.         Err.Raise errInvalidIndex, "vbdPolygon.Y"
  87.     End If
  88.  
  89.     Y = m_OriginalPoints(Index).Y
  90. End Property
  91. ' Set a Y coordinate.
  92. Property Let Y(ByVal Index As Integer, ByVal new_value As Single)
  93.     If (Index < 1) Or (Index > NumPoints) Then
  94.         Err.Raise errInvalidIndex, "vbdPolygon.Y"
  95.     End If
  96.  
  97.     m_OriginalPoints(Index).Y = new_value
  98. End Property
  99.  
  100. ' Start with an identity transformation.
  101. Private Sub Class_Initialize()
  102.     ' Initialize the drawing parameters.
  103.     InitializeDrawingProperties Me
  104.     m2Identity m_M
  105. End Sub
  106.  
  107. ' The user has selected a point.
  108. Private Sub m_Canvas_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
  109.     ' If we are drawing a rubberband line,
  110.     ' erase it.
  111.     If m_NumPoints > 0 Then m_Canvas.Line (m_StartX, m_StartY)-(m_LastX, m_LastY)
  112.  
  113.     ' If this is the first point, start using
  114.     ' dotted vbInvert mode.
  115.     If m_NumPoints = 0 Then
  116.         m_Canvas.DrawMode = vbInvert
  117.         m_Canvas.DrawStyle = vbDot
  118.         m_DrawingStarted = True
  119.     End If
  120.  
  121.     ' See if this is the left or right button.
  122.     If Button And vbLeftButton Then
  123.         ' It's the left button.
  124.         ' Add this point to the polygon.
  125.  
  126.         ' Add the new point.
  127.         m_NumPoints = m_NumPoints + 1
  128.         ReDim Preserve m_OriginalPoints(1 To m_NumPoints)
  129.         m_OriginalPoints(m_NumPoints).X = X
  130.         m_OriginalPoints(m_NumPoints).Y = Y
  131.  
  132.         ' Draw the line permanently.
  133.         m_Canvas.DrawMode = vbCopyPen
  134.         m_Canvas.DrawStyle = vbSolid
  135.         m_Canvas.Line (m_StartX, m_StartY)-(m_LastX, m_LastY)
  136.         m_Canvas.DrawMode = vbInvert
  137.         m_Canvas.DrawStyle = vbDot
  138.  
  139.         ' Start the next rubberband line.
  140.         m_StartX = X
  141.         m_StartY = Y
  142.         m_LastX = X
  143.         m_LastY = Y
  144.         m_Canvas.Line (m_StartX, m_StartY)-(m_LastX, m_LastY)
  145.     Else
  146.         ' It's the right button.
  147.         ' Stop building the polygon.
  148.  
  149.         ' Go back to vbCopyPen drawing mode.
  150.         m_Canvas.DrawMode = vbCopyPen
  151.  
  152.         ' Stop receiving events from the canvas.
  153.         Set m_Canvas = Nothing
  154.  
  155.         ' If we have at least 3 points, tell the
  156.         ' form to save us.
  157.         If m_NumPoints >= 3 Then
  158.             ' We have at least 3 points. Tell the
  159.             ' form to save us.
  160.             frmVbDraw.AddObject Me
  161.         Else
  162.             ' We do not have 3 points. Tell the
  163.             ' form to cancel us.
  164.             frmVbDraw.CancelObject
  165.         End If
  166.     End If
  167. End Sub
  168.  
  169. ' Continue drawing the rubberband line.
  170. Private Sub m_Canvas_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
  171.     If Not m_DrawingStarted Then Exit Sub
  172.  
  173.     ' Erase the old line.
  174.     m_Canvas.Line (m_StartX, m_StartY)-(m_LastX, m_LastY)
  175.  
  176.     ' Update the point.
  177.     m_LastX = X
  178.     m_LastY = Y
  179.  
  180.     ' Draw the new line.
  181.     m_Canvas.Line (m_StartX, m_StartY)-(m_LastX, m_LastY)
  182. End Sub
  183.  
  184.  
  185. Private Property Set vbdObject_Canvas(ByVal RHS As PictureBox)
  186.     Set m_Canvas = RHS
  187. End Property
  188.  
  189. Private Property Get vbdObject_Canvas() As PictureBox
  190.     Set vbdObject_Canvas = m_Canvas
  191. End Property
  192.  
  193. ' Clear the object's transformation.
  194. Private Sub vbdObject_ClearTransformation()
  195.     m2Identity m_M
  196. End Sub
  197. ' Add this transformation to the current one.
  198. Private Sub vbdObject_AddTransformation(M() As Single)
  199. Dim T(1 To 3, 1 To 3) As Single
  200.  
  201.     m2MatMultiply T, m_M, M
  202.     m2MatCopy m_M, T
  203. End Sub
  204.  
  205.  
  206. ' Draw the object in a metafile.
  207. Private Sub vbdObject_DrawInMetafile(ByVal mf_dc As Long)
  208.     ' Make sure we have at least 2 points.
  209.     If m_NumPoints < 2 Then Exit Sub
  210.  
  211.     SetMetafileDrawingParameters Me, mf_dc
  212.  
  213.     ' Draw the polygon.
  214.     TransformPoints
  215.     If IsClosed Then
  216.         Polygon mf_dc, m_TransformedPoints(1), m_NumPoints
  217.     Else
  218.         Polyline mf_dc, m_TransformedPoints(1), m_NumPoints
  219.     End If
  220.  
  221.     RestoreMetafileDrawingParameters mf_dc
  222. End Sub
  223. ' Return the object's DrawWidth.
  224. Public Property Get vbdObject_DrawWidth() As Integer
  225.     vbdObject_DrawWidth = m_DrawWidth
  226. End Property
  227. ' Set the object's DrawWidth.
  228. Public Property Let vbdObject_DrawWidth(ByVal new_value As Integer)
  229.     m_DrawWidth = new_value
  230. End Property
  231.  
  232. ' Return the object's DrawStyle.
  233. Public Property Get vbdObject_DrawStyle() As DrawStyleConstants
  234.     vbdObject_DrawStyle = m_DrawStyle
  235. End Property
  236. ' Set the object's DrawStyle.
  237. Public Property Let vbdObject_DrawStyle(ByVal new_value As DrawStyleConstants)
  238.     m_DrawStyle = new_value
  239. End Property
  240.  
  241. ' Return the object's ForeColor.
  242. Public Property Get vbdObject_ForeColor() As OLE_COLOR
  243.     vbdObject_ForeColor = m_ForeColor
  244. End Property
  245. ' Set the object's ForeColor.
  246. Public Property Let vbdObject_ForeColor(ByVal new_value As OLE_COLOR)
  247.     m_ForeColor = new_value
  248. End Property
  249.  
  250. ' Return the object's FillColor.
  251. Public Property Get vbdObject_FillColor() As OLE_COLOR
  252.     vbdObject_FillColor = m_FillColor
  253. End Property
  254. ' Set the object's FillColor.
  255. Public Property Let vbdObject_FillColor(ByVal new_value As OLE_COLOR)
  256.     m_FillColor = new_value
  257. End Property
  258.  
  259. ' Return the object's FillStyle.
  260. Public Property Get vbdObject_FillStyle() As FillStyleConstants
  261.     vbdObject_FillStyle = m_FillStyle
  262. End Property
  263. ' Set the object's FillStyle.
  264. Public Property Let vbdObject_FillStyle(ByVal new_value As FillStyleConstants)
  265.     m_FillStyle = new_value
  266. End Property
  267.  
  268. ' Return this object's bounds.
  269. Public Sub vbdObject_Bound(ByRef xmin As Single, ByRef ymin As Single, ByRef xmax As Single, ByRef ymax As Single)
  270. Dim i As Integer
  271.  
  272.     If m_NumPoints < 1 Then
  273.         xmin = 0
  274.         xmax = 0
  275.         ymin = 0
  276.         ymax = 0
  277.     Else
  278.         With m_TransformedPoints(1)
  279.             xmin = .X
  280.             xmax = xmin
  281.             ymin = .Y
  282.             ymax = ymin
  283.         End With
  284.  
  285.         For i = 2 To m_NumPoints
  286.             With m_TransformedPoints(i)
  287.                 If xmin > .X Then xmin = .X
  288.                 If xmax < .X Then xmax = .X
  289.                 If ymin > .Y Then ymin = .Y
  290.                 If ymax < .Y Then ymax = .Y
  291.             End With
  292.         Next i
  293.     End If
  294. End Sub
  295. ' Draw the object on the canvas.
  296. Public Sub vbdObject_Draw(ByVal pic As Object)
  297. Const GAP = 4
  298.  
  299. Dim xmin As Single
  300. Dim xmax As Single
  301. Dim ymin As Single
  302. Dim ymax As Single
  303.  
  304.     ' Make sure we have at least 2 points.
  305.     If m_NumPoints < 2 Then Exit Sub
  306.  
  307.     SetCanvasDrawingParameters Me, pic
  308.  
  309.     ' Draw the polygon.
  310.     TransformPoints
  311.     If IsClosed Then
  312.         Polygon pic.hdc, m_TransformedPoints(1), m_NumPoints
  313.     Else
  314.         Polyline pic.hdc, m_TransformedPoints(1), m_NumPoints
  315.     End If
  316.  
  317.     ' Highlight if necessary.
  318.     If m_Selected Then
  319.         vbdObject_Bound xmin, ymin, xmax, ymax
  320.         pic.DrawWidth = 1
  321.         pic.DrawStyle = vbSolid
  322.         pic.FillStyle = vbFSSolid
  323.         pic.FillColor = vbWhite
  324.         pic.Line (xmin, ymin)-Step(-GAP, -GAP), vbBlack, B
  325.         pic.Line (xmin, ymax)-Step(-GAP, GAP), vbBlack, B
  326.         pic.Line (xmax, ymin)-Step(GAP, -GAP), vbBlack, B
  327.         pic.Line (xmax, ymax)-Step(GAP, GAP), vbBlack, B
  328.     End If
  329. End Sub
  330. ' Apply the transformation matrix.
  331. Private Sub TransformPoints()
  332. Dim i As Integer
  333.  
  334.     ReDim m_TransformedPoints(1 To m_NumPoints)
  335.     For i = 1 To m_NumPoints
  336.         With m_OriginalPoints(i)
  337.             m_TransformedPoints(i).X = .X * m_M(1, 1) + .Y * m_M(2, 1) + m_M(3, 1)
  338.             m_TransformedPoints(i).Y = .X * m_M(1, 2) + .Y * m_M(2, 2) + m_M(3, 2)
  339.         End With
  340.     Next i
  341. End Sub
  342.  
  343. ' Set the object's Selected status.
  344. Private Property Let vbdObject_Selected(ByVal RHS As Boolean)
  345.     m_Selected = RHS
  346. End Property
  347. ' Return the object's Selected status.
  348. Private Property Get vbdObject_Selected() As Boolean
  349.     vbdObject_Selected = m_Selected
  350. End Property
  351.  
  352. ' Return True if the object is at this location.
  353. Private Function vbdObject_IsAt(ByVal X As Single, ByVal Y As Single) As Boolean
  354. Dim is_at As Boolean
  355.  
  356.     is_at = PolygonIsAt(IsClosed, X, Y, m_TransformedPoints)
  357.     If (Not is_at) And IsClosed And _
  358.         (m_FillStyle <> vbFSTransparent) _
  359.     Then
  360.         is_at = PointIsInPolygon(X, Y, m_TransformedPoints)
  361.     End If
  362.  
  363.     vbdObject_IsAt = is_at
  364. End Function
  365.  
  366. ' Initialize the object using a serialization string.
  367. ' The serialization does not include the
  368. ' ObjectType(...) part.
  369. Private Property Let vbdObject_Serialization(ByVal RHS As String)
  370. Dim token_name As String
  371. Dim token_value As String
  372. Dim next_x As Integer
  373. Dim next_y As Integer
  374.  
  375.     InitializeDrawingProperties Me
  376.     m2Identity m_M
  377.  
  378.     ' Read tokens until there are no more.
  379.     Do While Len(RHS) > 0
  380.         ' Read a token.
  381.         GetNamedToken RHS, token_name, token_value
  382.         Select Case token_name
  383.             Case "IsClosed"
  384.                 IsClosed = CBool(token_value)
  385.             Case "NumPoints"
  386.                 ' This allocates the m_X and m_Y arrays.
  387.                 NumPoints = CLng(token_value)
  388.                 next_x = 1
  389.                 next_y = 1
  390.             Case "X"
  391.                 X(next_x) = CSng(token_value)
  392.                 next_x = next_x + 1
  393.             Case "Y"
  394.                 Y(next_y) = CSng(token_value)
  395.                 next_y = next_y + 1
  396.             Case "Transformation"
  397.                 SetTransformationSerialization token_value, m_M
  398.             Case Else
  399.                 ReadDrawingPropertySerialization Me, token_name, token_value
  400.         End Select
  401.     Loop
  402. End Property
  403. ' Return a serialization string for the object.
  404. Public Property Get vbdObject_Serialization() As String
  405. Dim txt As String
  406. Dim i As Integer
  407.  
  408.     txt = DrawingPropertySerialization(Me)
  409.     txt = txt & TransformationSerialization(m_M)
  410.     txt = txt & " IsClosed(" & Format$(IsClosed) & ")"
  411.     txt = txt & " NumPoints(" & Format$(NumPoints) & ")"
  412.     For i = 1 To NumPoints
  413.         With m_OriginalPoints(i)
  414.             txt = txt & vbCrLf & "    X(" & Format$(.X) & ")"
  415.             txt = txt & " Y(" & Format$(.Y) & ")"
  416.         End With
  417.     Next i
  418.  
  419.     vbdObject_Serialization = "vbdPolygon(" & txt & ")"
  420. End Property
  421.  
  422.